home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
MPW_TOOL
/
TOOLS
/
TOOLS_WI
/
ICON_8
/
ICONX_FO
/
RLOCAL.C
< prev
next >
Wrap
Text File
|
1990-03-11
|
21KB
|
814 lines
/*
* Routines needed for different systems.
*/
#include <math.h>
#include "::h:config.h"
#include "::h:rt.h"
#include "rproto.h"
#include <ctype.h>
/*
* The following code is operating-system dependent [@rlocal.01].
* Routines needed by different systems.
*/
#if PORT
/* place for anything system-specific */
Deliberate Syntax Error
#endif /* PORT */
#if AMIGA
#if AZTEC_C
/*
* abs
*/
abs(i)
int i;
{
return ((i<0)? (-i) : i);
}
/*
* ldexp
*/
double ldexp(value,exp)
double value;
{
double retval = 1.0;
if(exp>0) {
while(exp-->0) retval *= 2.0;
} else if (exp<0) {
while(exp++<0) retval = retval / 2.0;
}
return value * retval;
}
/*
* abort()
*/
novalue abort()
{
fprintf(stderr,"ICON ERROR WITH ICONCORE SET\n");
fflush(stderr);
exit(1);
}
#ifdef SystemFnc
/*
* Aztec C version 3.6 does not support system(), but here is a substitute.
* This is a bonafide untested-original-it-just-compiles routine.
* Manx will probably implement system() before we fix this version...
*/
#include <ctype.h>
#define KLUDGE1 256
#define KLUDGE2 64
int system(s)
char *s;
{
char text[KLUDGE1], *cp=text;
char **av[KLUDGE2];
int ac = 0;
int l = strlen(s);
if (l >= KLUDGE1)
return -1;
strcpy(text,s);
av[ac++] = text;
while(*cp && ac<KLUDGE2-1) {
if (isspace(*cp)) {
*cp++ = '\0';
while(isspace(*cp))
cp++;
if (*cp)
av[ac++] = cp;
}
else {
cp++;
}
}
av[ac] = NULL;
return fexecv(av[0], av);
}
#endif /* SystemFnc */
#endif /* AZTEC_C */
#endif /* AMIGA */
#if ATARI_ST
#if LATTICE
long _STACK = 10240;
long _MNEED = 200000; /* reserve space for allocation (may be too large) */
#include <osbind.h>
/* Structure necessary for handling system time. */
struct tm {
short tm_year;
short tm_mon;
short tm_wday;
short tm_mday;
short tm_hour;
short tm_min;
short tm_sec;
};
struct tm *localtime(clock) /* fill structure with clock time */
int clock; /* millisecond timer value, if supplied; not used */
{
static struct tm tv;
unsigned int time, date;
time = Tgettime();
date = Tgetdate();
tv.tm_year = ((date >> 9) & 0x7f) + 80;
tv.tm_mon = ((date >> 5) & 0xf) - 1;
tv.tm_mday = date & 0x1f;
tv.tm_hour = (time >> 11) & 0x1f;
tv.tm_min = (time >> 5) & 0x3f;
tv.tm_sec = 2 * (time & 0x1f);
tv.tm_wday = weekday(tv.tm_mday,tv.tm_mon+1,tv.tm_year);
return(&tv);
}
weekday(day,month,year) /* find day of week from */
short day, month, year; /* day, month, and year */
{ /* Sunday..Saturday is 0..6 */
int index, yrndx, mondx;
if(month <= 2) { /* Jan or Feb month adjust */
month += 12;
year -= 1;
}
yrndx = year + (year / 4) - (year / 100) + (year / 400);
mondx = 2 * month + (3 * (month + 1)) / 5;
index = day + mondx + yrndx + 2;
return(index % 7);
}
time(ptime) /* return value of millisecond timer */
int *ptime;
{
int tmp, ssp; /* value of supervisor stack pointer */
static int *tmr = (int *) 0x04ba; /* addr of timer */
ssp = gemdos(0x20,0); /* enter supervisor mode */
tmp = *tmr * 5; /* get millisecond timer */
ssp = gemdos(0x20,ssp); /* enter programmer mode */
if(ptime != NULL)
*ptime = tmp;
return(tmp);
}
int brk(p)
char *p;
{
char *sbrk();
long int l, m;
l = (long int)p;
m = (long int)sbrk(0);
return((lsbrk((long) (l - m)) == 0) ? -1 : 0);
}
#ifdef LocalQsort
/* Shell sort with some enhancements from Knuth.. */
void qsort( base, nel, width, cmp ) /* was llqsort( ... */
char *base; /*-also kqsort( ...-*/
int nel;
int width;
int (*cmp)();
{
register int i, j;
long int gap;
int k, tmp ;
char *p1, *p2;
for( gap=1; gap <= nel; gap = 3*gap + 1 ) ;
for( gap /= 3; gap > 0 ; gap /= 3 )
for( i = gap; i < nel; i++ )
for( j = i-gap; j >= 0 ; j -= gap ) {
p1 = base + ( j * width);
p2 = base + ((j+gap) * width);
if( (*cmp)( p1, p2 ) <= 0 ) break;
for( k = width; --k >= 0 ;) {
tmp = *p1;
*p1++ = *p2;
*p2++ = tmp;
}
}
}
#endif /* LocalQsort */
#endif /* LATTICE */
#endif /* ATARI_ST */
#if HIGHC_386
#endif /* HIGHC_386 */
#if MACINTOSH
#if MPW
/*
** Special routines for Macintosh Programmer's Workshop
** implementation of the Icon Programming Language
*/
#include <Types.h>
#include <Events.h>
#include <OSUtils.h>
#define MaxBlockX MaxBlock /* MaxBlock Icon definition conflicts */
#undef MaxBlock /* with Mac Toolbox routine */
#include <Memory.h>
#define MaxBlock MaxBlockX
#undef MaxBlockX
#include <Errors.h>
/*
** Initialization and Termination Routines
*/
/*
** MacExit -- This function is installed by an onexit() call in MacInit
** -- it is called automatically when the program terminates.
*/
void
MacExit()
{
void ResetStack();
extern Ptr MemBlock;
ResetStack();
if (MemBlock != NULL) DisposPtr(MemBlock);
}
/*
** MacInit -- This function is called near the beginning of execution of
** iconx. It is called by our own brk/sbrk initialization routine.
*/
void
MacInit()
{
atexit(MacExit);
}
/*
** Brk and Sbrk Equivalents
*/
typedef Ptr caddr_t;
static caddr_t MemBlock, Break, Limit;
word xcodesize;
init_brk()
{
static short init = 0;
Size max, grow, size;
char *v;
extern word mstksize, statsize, ssize, abrsize;
if (!init) {
init = 1;
MacInit();
if ((v = getenv("ICONSIZE")) != NULL) { /* if ICONSIZE defined */
if ((size = atol(v)) <= 0) { /* if ICONSIZE negative */
max = MaxMem(&grow);
size = max + grow - (size < 0 ? -size : max / 4);
}
}
else { /* if ICONSIZE undefined */
size = xcodesize + mstksize + statsize + ssize + abrsize + 512;
}
if ((MemBlock = NewPtr(size)) == NULL) {
syserr("Unable to perform initial Icon memory allocation");
}
Break = MemBlock;
Limit = MemBlock + size;
}
return 1;
}
caddr_t
brk(addr)
caddr_t addr;
{
Size newsize;
if (!init_brk()) return (caddr_t)-1;
if (addr < MemBlock) return (caddr_t)-1;
if (addr < Limit) Break = addr;
else {
newsize = addr - MemBlock;
SetPtrSize(MemBlock, newsize);
if (MemError() != noErr) return (caddr_t)-1;
Break = Limit = addr;
}
return (caddr_t)0;
}
caddr_t
sbrk(incr)
int incr;
{
caddr_t start;
if (!init_brk()) return (caddr_t)-1;
start = Break;
if (incr != 0) {
if (brk(start + incr) == (caddr_t)-1) return (caddr_t)-1;
}
return start;
}
#endif /* MPW */
#endif /* MACINTOSH */
#if MSDOS
#if TURBO
extern unsigned _stklen = 8 * 1024;
#endif /* TURBO */
#if LATTICE
#include <error.h>
int _stack = (8 * 1024);
long int _mneed = (20 * 1024);
extern long int *sp;
long int **xsp = &sp; /* Used for rswitch.asm .. since 'sp' is a reserved */
/* symbol for the assembler.. */
extern char *statend; /* Indicator for when to use malloc for _GETBF */
int brk(p)
char *p;
{
char *sbrk();
long int l, m;
l = (long int)p;
m = (long int)sbrk((word)0);
if( lsbrk((long) (l - m) ) == 0) return -1;
else return 0;
}
novalue abort() /* Abort set to 'dump' icon data area.. */
{
#ifdef DeBugIconx
blkdump();
#endif /* DeBugIconx */
fflush(stderr);
fcloseall();
_exit(1);
}
#endif /* LATTICE */
#endif /* MSDOS */
#if MVS || VM
const int _staksize = (64*1024);
#endif /* MVS || VM */
#if OS2
#endif /* OS2 */
#if UNIX
#ifdef ATTM32
/*
* This file contains the routine necessary to allocate legal AT&T
* 3B2/15/4000 stack space for co-expression stacks.
*
* Legal stack region begins at 0xC0020000, and UNIX will grow stack space
* up to 50 Megabytes. 0xC0030000 should provide plenty of room for
* main C stack growth. Each time coexpr_salloc() is called, it
* adds mstksize (max main stack size) and returns a new address,
* meaning each coexpression stack is potentially as large as the main stack.
*/
/*
* coexp_salloc() - return pointer in legal stack space for start
* of a coexpression stack.
*/
pointer coexp_salloc()
{
static pointer sp = 0xC0030000 ; /* pointer to stack region */
sp += mstksize;
return sp;
}
#endif /* ATTM32 */
#if CONVEX
/* replacement pow() that allows negative ** integer */
#undef pow
double pow0 (base, exp)
double base, exp;
{ if (base >= 0) return pow (base, exp);
else {
long n = exp;
if (n != exp) runerr (-206, 0);
else if (n & 1) return -pow (-base, exp);
else return pow (-base, exp);}}
#endif /* CONVEX */
#endif /* UNIX */
#if VMS
#include dvidef
#include iodef
typedef struct _descr {
int length;
char *ptr;
} descriptor;
typedef struct _pipe {
long pid; /* process id of child */
long status; /* exit status of child */
long flags; /* LIB$SPAWN flags */
int channel; /* MBX channel number */
int efn; /* Event flag to wait for */
char mode; /* the open mode */
FILE *fptr; /* file pointer (for fun) */
unsigned running : 1; /* 1 if child is running */
} Pipe;
Pipe _pipes[_NFILE]; /* one for every open file */
#define NOWAIT 1
#define NOCLISYM 2
#define NOLOGNAM 4
#define NOKEYPAD 8
#define NOTIFY 16
#define NOCONTROL 32
#define SFLAGS (NOWAIT|NOKEYPAD|NOCONTROL)
/*
* popen - open a pipe command
* Last modified 2-Apr-86/chj
*
* popen("command", mode)
*/
FILE *popen(cmd, mode)
char *cmd;
char *mode;
{
FILE *pfile; /* the Pfile */
Pipe *pd; /* _pipe database */
descriptor mbxname; /* name of mailbox */
descriptor command; /* command string descriptor */
descriptor nl; /* null device descriptor */
char mname[65]; /* mailbox name string */
int chan; /* mailbox channel number */
int status; /* system service status */
int efn;
struct {
short len;
short code;
char *address;
char *retlen;
int last;
} itmlst;
if (!cmd || !mode)
return (0);
LIB$GET_EF(&efn);
if (efn == -1)
return (0);
if (_tolower(mode[0]) != 'r' && _tolower(mode[0]) != 'w')
return (0);
/* create and open the mailbox */
status = SYS$CREMBX(0, &chan, 0, 0, 0, 0, 0);
if (!(status & 1)) {
LIB$FREE_EF(&efn);
return (0);
}
itmlst.last = mbxname.length = 0;
itmlst.address = mbxname.ptr = mname;
itmlst.retlen = &mbxname.length;
itmlst.code = DVI$_DEVNAM;
itmlst.len = 64;
status = SYS$GETDVIW(0, chan, 0, &itmlst, 0, 0, 0, 0);
if (!(status & 1)) {
LIB$FREE_EF(&efn);
return (0);
}
mname[mbxname.length] = '\0';
pfile = fopen(mname, mode);
if (!pfile) {
LIB$FREE_EF(&efn);
SYS$DASSGN(chan);
return (0);
}
/* Save file information now */
pd = &_pipes[fileno(pfile)]; /* get Pipe pointer */
pd->mode = _tolower(mode[0]);
pd->fptr = pfile;
pd->pid = pd->status = pd->running = 0;
pd->flags = SFLAGS;
pd->channel = chan;
pd->efn = efn;
/* fork the command */
nl.length = strlen("_NL:");
nl.ptr = "_NL:";
command.length = strlen(cmd);
command.ptr = cmd;
status = LIB$SPAWN(&command,
(pd->mode == 'r') ? 0 : &mbxname, /* input file */
(pd->mode == 'r') ? &mbxname : 0, /* output file */
&pd->flags, 0, &pd->pid, &pd->status, &pd->efn, 0, 0, 0, 0);
if (!(status & 1)) {
LIB$FREE_EF(&efn);
SYS$DASSGN(chan);
return (0);
} else {
pd->running = 1;
}
return (pfile);
}
/*
* pclose - close a pipe
* Last modified 2-Apr-86/chj
*
*/
pclose(pfile)
FILE *pfile;
{
Pipe *pd;
int status;
int fstatus;
pd = fileno(pfile) ? &_pipes[fileno(pfile)] : 0;
if (pd == NULL)
return (-1);
fflush(pd->fptr); /* flush buffers */
fstatus = fclose(pfile);
if (pd->mode == 'w') {
status = SYS$QIOW(0, pd->channel, IO$_WRITEOF, 0, 0, 0, 0, 0, 0, 0, 0, 0);
SYS$WFLOR(pd->efn, 1 << (pd->efn % 32));
}
SYS$DASSGN(pd->channel);
LIB$FREE_EF(&pd->efn);
pd->running = 0;
return (fstatus);
}
/*
* redirect(&argc,argv,nfargs) - redirect standard I/O
* int *argc number of command arguments (from call to main)
* char *argv[] command argument list (from call to main)
* int nfargs number of filename arguments to process
*
* argc and argv will be adjusted by redirect.
*
* redirect processes a program's command argument list and handles redirection
* of stdin, and stdout. Any arguments which redirect I/O are removed from the
* argument list, and argc is adjusted accordingly. redirect would typically be
* called as the first statement in the main program.
*
* Files are redirected based on syntax or position of command arguments.
* Arguments of the following forms always redirect a file:
*
* <file redirects standard input to read the given file
* >file redirects standard output to write to the given file
* >>file redirects standard output to append to the given file
*
* It is often useful to allow alternate input and output files as the
* first two command arguments without requiring the <file and >file
* syntax. If the nfargs argument to redirect is 2 or more then the
* first two command arguments, if supplied, will be interpreted in this
* manner: the first argument replaces stdin and the second stdout.
* A filename of "-" may be specified to occupy a position without
* performing any redirection.
*
* If nfargs is 1, only the first argument will be considered and will
* replace standard input if given. Any arguments processed by setting
* nfargs > 0 will be removed from the argument list, and again argc will
* be adjusted. Positional redirection follows syntax-specified
* redirection and therefore overrides it.
*
*/
redirect(argc,argv,nfargs)
int *argc, nfargs;
char *argv[];
{
int i;
i = 1;
while (i < *argc) { /* for every command argument... */
switch (argv[i][0]) { /* check first character */
case '<': /* <file redirects stdin */
filearg(argc,argv,i,1,stdin,"r");
break;
case '>': /* >file or >>file redirects stdout */
if (argv[i][1] == '>')
filearg(argc,argv,i,2,stdout,"a");
else
filearg(argc,argv,i,1,stdout,"w");
break;
default: /* not recognized, go on to next arg */
i++;
}
}
if (nfargs >= 1 && *argc > 1) /* if positional redirection & 1 arg */
filearg(argc,argv,1,0,stdin,"r"); /* then redirect stdin */
if (nfargs >= 2 && *argc > 1) /* likewise for 2nd arg if wanted */
filearg(argc,argv,1,0,stdout,"w");/* redirect stdout */
}
/* filearg(&argc,argv,n,i,fp,mode) - redirect and remove file argument
* int *argc number of command arguments (from call to main)
* char *argv[] command argument list (from call to main)
* int n argv entry to use as file name and then delete
* int i first character of file name to use (skip '<' etc.)
* FILE *fp file pointer for file to reopen (typically stdin etc.)
* char mode[] file access mode (see freopen spec)
*/
filearg(argc,argv,n,i,fp,mode)
int *argc, n, i;
char *argv[], mode[];
FILE *fp;
{
if (strcmp(argv[n]+i,"-")) /* alter file if arg not "-" */
fp = freopen(argv[n]+i,mode,fp);
if (fp == NULL) { /* abort on error */
fprintf(stderr,"%%can't open %s",argv[n]+i);
exit(ErrorExit);
}
for ( ; n < *argc; n++) /* move down following arguments */
argv[n] = argv[n+1];
*argc = *argc - 1; /* decrement argument count */
}
/* Special versions of sbrk() and brk() for use by Icon under VMS.
* #defines in define.h actually rename these to vms_brk and vms_sbrk.
*
* For historical reasons, Icon assumes it can repeatedly call brk/sbrk
* and always get contiguous chunks. This was made to work under Unix by
* overloading the definitions of malloc and friends, the only other callers
* of sbrk, and making them return Icon-managed memory.
* Under VMS, sbrk is not the lowest-level system interface. It gets memory
* from underlying VMS routines such as SYS$EXPREG. These routines are also
* called by others, for example when a file is opened; so successive sbrk
* calls may return nonadjacent chunks. This makes overloading malloc and
* friends futile.
*
* The routines below replace sbrk and brk for Icon (only) under VMS. They
* provide the continuously growing memory Icon needs without relying on
* special privileges or unusually large quotas. Like the Unix solution and
* earlier VMS attempts, this is an empirical solution and may need further
* revision as the system changes. But we hope not.
*
* The Icon interpreter is loaded beginning at address 0 and grows upward as
* it requests more memory through sbrk. The C stack grows downward from
* 0x7FFFFFFF. We're going to draw a line to divide the address space, then
* force the C and VMS runtime systems to put anything they need above it;
* then sbrk can grow the program region unimpeded up to the line.
*
* The line is drawn MAXMEM bytes beyond the start of the sbrk region. MAXMEM
* is an environment variable (logical name to VMS) with a default as given in
* define.h. Large values cost CPU and real time expended at process exit; we
* don't know why. On an 8600 the cost was very roughly .04 CP sec / megabyte.
*
* When first called, sbrk expands the program region by one page to get a
* starting address. A limit address is calculated by adding MAXMEM. A single
* page created just below the limit address "draws the line" and causes the
* VMS runtime system to allocate anything it needs above that point. sbrk
* creates pages between base and limit as needed.
*
* Possible errors and their manifestations:
*
* MAXMEM too large to initialize sbrk:
* error in startup code: value of MAXMEM too large
*
* MAXMEM too small to initialize sbrk:
* error in startup code: value of MAXMEM too small
*
* MAXMEM too small for subsequent brk/sbrk growth
* Run-time error 351: insufficient MAXMEM limit
*
* MAXMEM okay but insufficient user quota for needed memory:
* Run-time error 303: unable to expand memory region
*
* unexpected ("can't happen") failures of system calls:
* these produce their standard VMS error message
*
* unexpected intrusion into the sbrk region by the runtime system:
* unknown, but undoubtedly ugly
*/
#define PageSize 512 /* size of a VMS page */
#define MaxP0 0x40000000 /* first address beyond the P0 region */
#include <stsdef.h>
word memsize = MaxMem; /* set from environment variable MAXMEM */
/* sbrk(incr) - adjust the break value by incr, rounding up to a page.
* returns the new break value, or -1 if unsuccessful.
*/
char *
sbrk(incr)
int incr;
{
static char *base; /* base of the sbrk region */
static char *curr; /* current break value (end+1) */
static char *limit; /* region limit ("the line") */
char *range[2], *p; /* scratch for system calls */
int s; /* status return from calls */
/* initialization code */
if (!base) {
s = sys$expreg(1,range,0,0); /* expand P0 to get base address */
if (!(s & STS$M_SUCCESS))
exit(s); /* couldn't get one page?! */
base = curr = range[0]; /* initialize empty sbrk region */
memsize = (memsize + PageSize - 1) & -PageSize;
/* round memsize to page boundary */
limit = base + memsize; /* calculate sbrk region limit*/
if (limit > MaxP0)
limit = MaxP0; /* limit to legal values */
if (limit <= base)
error("value of MAXMEM too small"); /* can't even start */
range[0] = range[1] = limit-1;
s = sys$cretva(range,range,0); /* get a page there to draw the line */
if (!(s & STS$M_SUCCESS))
error("value of MAXMEM too large"); /* can't even start */
}
if (incr > 0) {
/* grow the region */
if (curr + incr > limit) /* check address space available */
fatalerr(-351,NULL); /* oops, MAXMEM too small */
range[0] = curr;
range[1] = curr + incr - 1;
s = sys$cretva(range,range,0); /* ask for the pages */
if (!(s & STS$M_SUCCESS))
return (char *) -1; /* failed, quota exceeded */
curr = range[1] + 1; /* set new break value as returned */
} else if (incr < 0) {
/* shrink the region (not expected to be used). does not actually
* return the memory, but does make it available for reuse. */
curr -= -incr & -PageSize;
}
/* return the current break value */
return curr;
}
/* brk(addr) - set the break address to the given value, rounded up to a page.
* returns 0 if successful, -1 if not.
*/
char *
brk(addr)
char *addr;
{
return ((sbrk(addr-sbrk(0))) == (char *) -1 ? (char *) -1 : 0);
}
#endif /* VMS */
/*
* End of operating-system specific code.
*/
static char x; /* avoid empty module */